#include "LogFile.h"

namespace Logger
{
    LogFile::LogFile(const std::string &baseName, off_t rollSize, int rollCheckEveryN, int flushInterval)
        : baseName_(baseName),
          rollSize_(rollSize),
          rollCheckEveryN_(rollCheckEveryN),
          flushInterval_(flushInterval)
    {
        this->rollFile(); // 重新启动时可能没有log文件，调用创建
    }

    bool LogFile::rollFile()
    {
        time_t now{};
        std::string logName = getLogFileName(this->baseName_, &now);

        // / sDaySeconds整数除法得到1970-01-01 00:00:00 UTC-现在的天数
        // * sDaySeconds得到当天0点的时间戳秒数
        time_t curDayStart = now / sDaySeconds * sDaySeconds;
        if (now <= this->lastRoll_)
        {
            return false;
        }

        // 更新参数
        this->startPeriod_ = curDayStart;
        this->lastRoll_ = now;
        this->lastFlush_ = now;
        // 指向新文件
        this->file_.reset(new Logger::FileUtil(logName.c_str()));
        return true;
    }

    // testLogger-20250712:133926.log
    std::string LogFile::getLogFileName(const std::string &baseName, time_t *now)
    {
        std::string logName{};
        logName.reserve(baseName.size() + 64);
        logName = baseName;

        struct tm tm1{};
        *now = ::time(nullptr);
        ::localtime_r(now, &tm1);
        char timeBuf[64]{};
        ::strftime(timeBuf, sizeof(timeBuf), "-%Y%m%d:%H%M%S", &tm1);

        logName += timeBuf;
        logName += ".log";
        return logName;
    }

    void LogFile::append(const char *data, int size)
    {
        std::lock_guard<std::mutex> lock(this->mtx_);
        this->appendInlock(data, size);
    }

    void LogFile::appendInlock(const char *data, int size)
    {
        this->file_->write(data, size);

        time_t now = ::time(nullptr);
        ++this->writeCnt_;

        // 双重检查需要滚动：
        // 1.写入大小超过滚动大小
        // 2.写入次数超过阈值且时间跨天
        if (this->file_->getWrittenBytes() > this->rollSize_)
        {
            this->rollFile();
        }
        // 如果每次写入都做时间周期判断会影响性能，所以增加写入次数阈值判断
        else if (this->writeCnt_ >= this->rollCheckEveryN_)
        {
            this->writeCnt_ = 0;

            time_t curPeriod = now / sDaySeconds * sDaySeconds;
            if (curPeriod != this->startPeriod_)
            {
                this->rollFile();
            }
        }

        // 定时内存刷入磁盘
        if (now - this->lastFlush_ > this->flushInterval_)
        {
            this->lastFlush_ = now;
            this->file_->flush();
        }
    }

    void LogFile::flush()
    {
        this->file_->flush();
    }
} // namespace Logger
